﻿using Books.Model;
using Books.SQLite;
using Books.ViewModel;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Microsoft.Practices.ServiceLocation;
using Services.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.BackgroundTransfer;
using Windows.Storage;
using Windows.Web;

namespace Books.Common
{
    /// <summary>
    /// http://www.piotrwalat.net/downloading-files-in-windows-8-apps-using-background-transfer-feature/
    /// </summary>
    public class HandleDownLoadFile : ViewModelBase, IHandleDownLoadFile, IDisposable
    {

        List<DownloadOperation> downloadOperation;
        CancellationTokenSource cancellationToken;
        private bool buttonCancel;
        private bool buttonDownload;
        private bool buttonPauseResume;
        private string textBlockProgress;
        private double progressBarDownload;
        public static string BookId = string.Empty;
        public double ProgressBarDownload
        {
            get { return progressBarDownload; }
            set { Set(ref progressBarDownload, value); }
        }
        public string TextBlockProgress
        {
            get { return textBlockProgress; }
            set { Set(ref textBlockProgress, value); }
        }
        public bool ButtonPauseResume
        {
            get { return buttonPauseResume; }
            set
            {
                Set(ref buttonPauseResume, value);
            }
        }
        public bool ButtonDownload
        {
            get { return buttonDownload; }
            set
            {
                buttonDownload = value;
                Set(ref buttonDownload, value);
            }
        }
        public bool ButtonCancel
        {
            get { return buttonCancel; }
            set
            {
                buttonCancel = value;
                Set(ref buttonCancel, value);
            }
        }
        private List<FileDownLoadComplete> filesDownload;
        private ObservableCollection<ChapterList> listChappterDownload;
        private IBookDetailViewModel bookDetail
        {
            get { return ServiceLocator.Current.GetInstance<IBookDetailViewModel>(); }
        }

        public ObservableCollection<ChapterList> ListChappterDownload
        {
            get
            {
                if (listChappterDownload == null)
                    listChappterDownload = new ObservableCollection<ChapterList>();
                return listChappterDownload;
            }
            set { Set(ref listChappterDownload, value); }
        }

        public HandleDownLoadFile()
        {
            cancellationToken = new CancellationTokenSource();
            DiscoverActiveDownloadsAsync();
        }
        public void Dispose()
        {
            if (cancellationToken != null)
            {
                cancellationToken.Dispose();
                cancellationToken = null;
            }
            GC.SuppressFinalize(this);
        }
        private RelayCommand<List<ChapterList>> downloadAll;
        public RelayCommand<List<ChapterList>> DownloadAll
        {
            get
            {
                if (downloadAll == null)
                    downloadAll = new RelayCommand<List<ChapterList>>(p => HandleDownloadAll(p));
                return downloadAll;
            }
        }
        private void HandleDownloadAll(List<ChapterList> listChapter)
        {
            BookId = bookDetail.DataBooksDetail.book_detail.book_id;
            CheckFilesBeforeDownload(listChapter);
        }
        private async Task DiscoverActiveDownloadsAsync()
        {
            downloadOperation = new List<DownloadOperation>();
            IReadOnlyList<DownloadOperation> downloads = await BackgroundDownloader.GetCurrentDownloadsAsync(); ;

            try
            {
                downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
            }
            catch (Exception ex)
            {
                return;
            }

            // Log("Loading background downloads: " + downloads.Count);

            if (downloads.Count > 0)
            {
                List<Task> tasks = new List<Task>();
                foreach (DownloadOperation download in downloads)
                {
                    tasks.Add(HandleDownloadAsync(download, false));
                }
                await Task.WhenAll(tasks);
            }
        }
        private async void CheckFilesBeforeDownload(List<ChapterList> listChapter)
        {
            foreach (var m in listChapter)
            {
                var fileName = GetFileName.FileName(m.chapter_id, new Uri(m.audio_link));
                var checkExitsFileDownloadComplete = ManagerFilesDownloadComplete.CheckExitsFile(fileName);
                if (checkExitsFileDownloadComplete == null)
                    ListChappterDownload.Add(m);
            }
            if (ListChappterDownload.Count > 0)
            {
                foreach (var filesDownload in listChapter)
                {
                    var fileName = GetFileName.FileName(filesDownload.chapter_id, new Uri(filesDownload.audio_link));
                    StartDownload(new Uri(filesDownload.audio_link), fileName, BackgroundTransferPriority.High, false);
                }

            }

        }
       
        private async void StartDownload(Uri source, string fileName, BackgroundTransferPriority priority, bool requestUnconstrainedDownload)
        {
            StorageFolder folder = null;
            var getFolderInfo = await ApplicationData.Current.LocalFolder.TryGetItemAsync(BookId);
            if (getFolderInfo == null)
                folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(BookId);
            else
                folder = await ApplicationData.Current.LocalFolder.GetFolderAsync(BookId);

            StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);

            BackgroundDownloader downloader = new BackgroundDownloader();
            DownloadOperation download = downloader.CreateDownload(source, file);
            download.Priority = priority;
            downloader.CostPolicy = BackgroundTransferCostPolicy.UnrestrictedOnly;
            if (!requestUnconstrainedDownload)
            {
                await HandleDownloadAsync(download, true);
                return;
            }
            List<DownloadOperation> requestOperations = new List<DownloadOperation>();
            requestOperations.Add(download);

            // If the app isn't actively being used, at some point the system may slow down or pause long running
            // downloads. The purpose of this behavior is to increase the device's battery life.
            // By requesting unconstrained downloads, the app can request the system to not suspend any of the
            // downloads in the list for power saving reasons.
            // Use this API with caution since it not only may reduce battery life, but it may show a prompt to
            // the user.
            UnconstrainedTransferRequestResult result;
            try
            {
                result = await BackgroundDownloader.RequestUnconstrainedDownloadsAsync(requestOperations);
            }
            catch (NotImplementedException)
            {
                return;
            }
            await HandleDownloadAsync(download, true);
        }
        private async Task HandleDownloadAsync(DownloadOperation download, bool start)
        {
            try
            {
                TextBlockProgress = "Initializing....";
                downloadOperation.Add(download);
                Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress);
                if (start)
                {
                    // Start the download and attach a progress handler.
                    await download.StartAsync().AsTask(cancellationToken.Token, progressCallback).ConfigureAwait(true);
                }
                else
                {
                    // The download was already running when the application started, re-attach the progress handler.
                    await download.AttachAsync().AsTask(cancellationToken.Token, progressCallback).ConfigureAwait(true);
                }

                ResponseInformation response = download.GetResponseInformation();

                TextBlockProgress = String.Format("Download Completed");
            }
            catch (TaskCanceledException)
            {
                TextBlockProgress = "Canceled: " + download.Guid;
            }
            catch (Exception ex)
            {
                if (!IsExceptionHandled("Execution error", ex, download))
                {
                    throw;
                }
            }
            finally
            {
                downloadOperation.Remove(download);
            }
        }
        private void DownloadProgress(DownloadOperation download)
        {
            int progress = (int)(100 * ((double)download.Progress.BytesReceived / (double)download.Progress.TotalBytesToReceive));
            double percent = 100;
            if (download.Progress.TotalBytesToReceive > 0)
            {
                percent = download.Progress.BytesReceived * 100 / download.Progress.TotalBytesToReceive;
                ProgressBarDownload = percent;
            }

            TextBlockProgress = "Download complete.";

            if (download.Progress.HasRestarted)
            {
                TextBlockProgress = " - Download restarted";
            }

            if (download.Progress.HasResponseChanged)
            {
                // We've received new response headers from the server.
                TextBlockProgress = String.Format("{0} of {1} kb. downloaded - %{2} complete.", download.Progress.BytesReceived / 1024, download.Progress.TotalBytesToReceive / 1024, progress);

                // If you want to stream the response data this is a good time to start.
                // download.GetResultStreamAt(0);
            }
        }



        private bool IsExceptionHandled(string title, Exception ex, DownloadOperation download = null)
        {
            WebErrorStatus error = BackgroundTransferError.GetStatus(ex.HResult);
            if (error == WebErrorStatus.Unknown)
            {
                return false;
            }

            if (download == null)
            {
                TextBlockProgress = String.Format(CultureInfo.CurrentCulture, "Error: {0}: {1}", title, error);
            }
            else
            {
                TextBlockProgress = String.Format(CultureInfo.CurrentCulture, "Error: {0} - {1}: {2}", download.Guid, title, error);
            }
            return true;
        }
        //async void InitDownload()
        //{
        //    IReadOnlyList<DownloadOperation> downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
        //    if (downloads.Count > 0)
        //    {
        //        downloadOperation =new List<DownloadOperation>(downloads.First());
        //        cancellationToken = new CancellationTokenSource();
        //        Progress<DownloadOperation> progress = new Progress<DownloadOperation>(progressChanged);
        //        ButtonDownload = false;
        //        ButtonCancel = true;
        //        ButtonPauseResume = true;
        //        try
        //        {
        //            TextBlockProgress = "Initializing...";
        //            await downloadOperation.AttachAsync().AsTask(cancellationToken.Token, progress);
        //        }
        //        catch (TaskCanceledException)
        //        {
        //            TextBlockProgress = "Download canceled.";
        //            downloadOperation.ResultFile.DeleteAsync().GetResults();
        //            // ButtonPauseResume.Content = "Resume";
        //            ButtonCancel = false;
        //            ButtonCancel = false;
        //            ButtonPauseResume = false;
        //            ButtonDownload = true;
        //            downloadOperation = null;
        //        }
        //    }
        //}
        //public async Task DownloadFile(string url, string chapter_id)
        //{

        //    var uri = new Uri(url);
        //    var fileNameDownload = GetFileName(chapter_id, uri);

        //    StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(fileNameDownload,
        //        CreationCollisionOption.ReplaceExisting);
        //    downloadOperation = backgroundDownloader.CreateDownload(uri, file);
        //    Progress<DownloadOperation> progress = new Progress<DownloadOperation>(progressChanged);
        //    cancellationToken = new CancellationTokenSource();
        //    ButtonDownload = false;
        //    ButtonCancel = true;
        //    ButtonPauseResume = true;
        //    try
        //    {
        //        TextBlockProgress = "Initializing...";
        //        await downloadOperation.StartAsync().AsTask(cancellationToken.Token, progress);
        //    }
        //    catch (TaskCanceledException)
        //    {
        //        TextBlockProgress = "Download canceled.";
        //        downloadOperation.ResultFile.DeleteAsync().GetResults();
        //        // ButtonPauseResume.Content = "Resume";
        //        ButtonCancel = false;
        //        ButtonCancel = false;
        //        ButtonPauseResume = false;
        //        ButtonDownload = true;
        //        downloadOperation = null;
        //    }
        //    //}
        //}

        //private void progressChanged(DownloadOperation downloadOperation)
        //{
        //    int progress = (int)(100 * ((double)downloadOperation.Progress.BytesReceived / (double)downloadOperation.Progress.TotalBytesToReceive));
        //    textBlockProgress = String.Format("{0} of {1} kb. downloaded - %{2} complete.", downloadOperation.Progress.BytesReceived / 1024, downloadOperation.Progress.TotalBytesToReceive / 1024, progress);
        //    progressBarDownload = progress;
        //    switch (downloadOperation.Progress.Status)
        //    {
        //        case BackgroundTransferStatus.Running:
        //            {
        //                TextBlockProgress = String.Format("{0} of {1} kb. downloaded - %{2} complete.", downloadOperation.Progress.BytesReceived / 1024, downloadOperation.Progress.TotalBytesToReceive / 1024, progress);
        //                //ButtonPauseResume.Content = "Pause";
        //                break;
        //            }
        //        case BackgroundTransferStatus.PausedByApplication:
        //            {
        //                TextBlockProgress = "Download paused.";
        //                //ButtonPauseResume.Content = "Resume";
        //                break;
        //            }
        //        case BackgroundTransferStatus.PausedCostedNetwork:
        //            {
        //                TextBlockProgress = "Download paused because of metered connection.";
        //                break;
        //            }
        //        case BackgroundTransferStatus.PausedNoNetwork:
        //            {
        //                TextBlockProgress = "No network detected. Please check your internet connection.";
        //                break;
        //            }
        //        case BackgroundTransferStatus.Error:
        //            {
        //                TextBlockProgress = "An error occured while downloading.";
        //                break;
        //            }
        //    }
        //    if (progress >= 100)
        //    {
        //        TextBlockProgress = "Download complete.";
        //        ButtonCancel = false;
        //        ButtonPauseResume = false;
        //        ButtonDownload = true;
        //        downloadOperation = null;
        //    }
        //}

        //private void ButtonPauseResumeClick()
        //{
        //    if (ButtonPauseResume)
        //    {
        //        try
        //        {
        //            downloadOperation.Pause();
        //        }
        //        catch (InvalidOperationException)
        //        {

        //        }
        //    }
        //    else
        //    {
        //        try
        //        {
        //            downloadOperation.Resume();
        //        }
        //        catch (InvalidOperationException)
        //        {
        //        }
        //    }
        //}
        //private void ButtonCancelClick()
        //{
        //    cancellationToken.Cancel();
        //    cancellationToken.Dispose();
        //}

        //private DownloadOperation activeDownload;
        //private double downloadProgress;

        //public double DownloadProgress
        //{
        //    get { return downloadProgress; }
        //    set
        //    {
        //        downloadProgress = value;
        //        RaisePropertyChanged("DownloadProgress");
        //    }
        //}
        //public HandleDownLoadFile()
        //{

        //}
        //private async Task LoadActiveDownloadsAsync()
        //{
        //    IReadOnlyList<DownloadOperation> downloads = null;
        //    downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
        //    if (downloads.Count > 0)
        //    {
        //        //for simplicity we support only one download
        //        await ResumeDownloadAsync(downloads.First());
        //    }
        //}
        //public async Task DownloadFile(string url, string bookId)
        //{
        //    var uri = new Uri(url);
        //    var downloader = new BackgroundDownloader();
        //    StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(bookId,
        //        CreationCollisionOption.ReplaceExisting);
        //    DownloadOperation download = downloader.CreateDownload(uri, file);
        //    await StartDownloadAsync(download);
        //}

        //private async Task ResumeDownloadAsync(DownloadOperation downloadOperation)
        //{
        //    //DownloadButton.IsEnabled = false;
        //    activeDownload = downloadOperation;
        //    var progress = new Progress<DownloadOperation>(ProgressCallback);
        //    await downloadOperation.AttachAsync().AsTask(progress);
        //}

        //private void ProgressCallback(DownloadOperation obj)
        //{
        //    double progress = ((double)obj.Progress.BytesReceived / obj.Progress.TotalBytesToReceive);
        //    DownloadProgress = progress * 100;
        //    if (progress >= 1.0)
        //    {
        //        activeDownload = null;
        //        //DownloadButton.IsEnabled = true;
        //    }
        //}
        //private async Task StartDownloadAsync(DownloadOperation downloadOperation)
        //{
        //    //DownloadButton.IsEnabled = false;
        //    activeDownload = downloadOperation;
        //    var progress = new Progress<DownloadOperation>(ProgressCallback);
        //    await downloadOperation.StartAsync().AsTask(progress);
        //}

        public Task DownloadFile(ChapterList url, string bookId)
        {
            BookId = bookId;
            List<ChapterList> listChapter = new List<ChapterList>();
            listChapter.Add(url);
            HandleDownloadAll(listChapter);
            return null;
        }
    }
}
